#!/usr/bin/env python
# Copyright(c) 2010 Nuttachat Wisittipanit. All rights reserved.

from mahbo.lib import (GUTIBD,)

from minings import (Param,SVMpm,)

import xlwt,numpy,interval
from copy import deepcopy


class ComparisonReport(object):
    
    def __init__(self,**kwargs):
        self.output_file    = ''
        #self.mset -> {'rdp8level1': MainSet instance, ..}
        #from GUTMTPS class
        self.mset           = {}
        #.gutlhpcr -> GUTMTPSLHPCR instance
        self.gutlhpcr       = None
        self.__dict__.update(kwargs)
        
    def xcelRecord(self):
        #Excel properties
        self.RDP8_s_n               = 'RDP8'
        self.RDP10_s_n              = 'RDP10'
        self.ALH_s_n                = 'ALH'
        self.VS_s_n                 = 'VSALL'
        self.book                   = xlwt.Workbook()
        self.sheet                  = {}
        self.sheet[self.RDP8_s_n]   = self.book.add_sheet(self.RDP8_s_n     ,cell_overwrite_ok = True)
        self.sheet[self.RDP10_s_n]  = self.book.add_sheet(self.RDP10_s_n    ,cell_overwrite_ok = True)
        self.sheet[self.ALH_s_n]    = self.book.add_sheet(self.ALH_s_n    ,cell_overwrite_ok = True)
        self.sheet[self.VS_s_n]     = self.book.add_sheet(self.VS_s_n       ,cell_overwrite_ok = True)
        self.col_width              = 6000
        self.setProperties()
        self.dataCollection()
        self.startRecording()
        self.saveBook()
    
    def findMajor(self,subname):
        #Find .Major (of MC instance) from subname
        gg  = subname.split('__')
        if 'Healthy Control' in gg:
            Major           = [u for u in gg if u != 'Healthy Control'][0]
        else:
            for k in gg:
                #k -> 'Crohn_Lumen' or 'Crohn_Sigmoid'
                lmfind      = k.split('_')
                if 'Lumen' in lmfind:
                    Major   = k
                    break
        return Major
    
    def setProperties(self):
        self.s_list_a       = ['Entire','Ileum','Colon','Sigmoid','Lumen',]
        self.s_list_b       = ['Ileum_Lumen','Colon_Lumen','Sigmoid_Lumen',]
        self.s_list_all     = ['Entire','Ileum','Colon','Sigmoid','Lumen','Ileum_Lumen','Colon_Lumen','Sigmoid_Lumen']
        self.d_list         = ['Crohn','Ulcerative Colitis',]
        self.d_list_a       = ['Crohn','Ulcerative Colitis','Healthy Control',]
        self.u_list_all     = ['Crohn','Ulcerative Colitis','Crohn_Lumen','Ulcerative Colitis_Lumen','Healthy Control_Lumen']
        self.u_list_norm    = ['Crohn','Ulcerative Colitis',]
        self.u_list_lumen   = ['Crohn_Lumen','Ulcerative Colitis_Lumen','Healthy Control_Lumen',]
        self.vs_list        = ['Ileum vs Lumen','Colon vs Lumen','Sigmoid vs Lumen',]
        self.t_list         = ['FS_FULL','FS_RELIEF','FS_BOTH',]
        #for xcel
        self.rdp8           = 'RDP8'
        self.rdp10          = 'RDP10'     
            
    def dataCollection(self):      
        self.mset_sort  = self.mset.keys()
        self.mset_sort.sort() 
        #Find data detail for MTPS
        #collect -> {'rdp8level1': MC instance, ..}
        self.collect    = {}
        for level in self.mset_sort:
            #mainset -> MainSet instance
            mainset             = self.mset[level]
            dset                = mainset.dset
            dsort               = mainset.dsort
            self.collect[level] = self.dataDetail(MC(),dset,dsort)
        #Find data detail for LHPCR
        #.lhpcr_mc -> MC instance
        self.lhpcr_mc   = self.dataDetail(MC(),self.gutlhpcr.dset,self.gutlhpcr.dsort)
        #Find data average for MTPS
        for level in self.collect:
            self.collect[level] = self.dataAverage(self.collect[level])
        #Find data average for LHPCR
        self.lhpcr_mc   = self.dataAverage(self.lhpcr_mc)
        #Find Best Level for MTPS
        self.bl         = BestLevel()
        for rdptype in GUTIBD.rdpType.LIST:
            #rdptype -> '8'
            #mn      -> 'RDP8'
            mn      = 'RDP%s' % rdptype
            #h       -> {'Crohn': {'FS_FULL'    : BestReport instance,
            #                      'FS_RELIEF'  : BestReport instance,
            #                      'FS_BOTH'    : BestReport instance,
            #                      }, ..}
            h       = getattr(self.bl,mn)
            for i in self.u_list_all:
                #i   -> 'Crohn'
                h[i]                = {}
                self.bl.LHPCR[i]    = {}
                for j in self.t_list:
                    #j -> 'FS_FULL'
                    gg          = []
                    if   rdptype == GUTIBD.rdpType.Eight:
                        slist   = GUTIBD.rdpList.LIST
                    elif rdptype == GUTIBD.rdpType.Ten:
                        slist   = GUTIBD.rdpList.LIST10
                    for rdplevel in slist:
                        rdpdbname   = self.rdp2dbName(rdplevel,rdptype)
                        aa          = self.collect[rdpdbname].FS[i][j].aa
                        gg.append((aa,rdpdbname,self.collect[rdpdbname].FS[i][j]))
                    gg.sort(reverse = True)
                    win_mtps    = gg[0]
                    br          = BestReport(level = win_mtps[1],
                                             avg   = win_mtps[2],
                                             )
                    h[i][j]     = br 
                    #LHPCR
                    br_lhpcr            = BestReport(level  = 'N/A'                     ,
                                                     avg    = self.lhpcr_mc.FS[i][j]    ,
                                                     ) 
                    self.bl.LHPCR[i][j] = br_lhpcr
        #find Best of Both and All
        for i in self.u_list_all:
            #i   -> 'Crohn'
            self.bl.Both[i] = {}
            self.bl.All[i]  = {}
            for j in self.t_list:
                #j -> 'FS_FULL'
                gg          = []
                ggAll       = []
                for rdptype in GUTIBD.rdpType.LIST:
                    #rdptype -> '8'
                    #mn      -> 'RDP8'
                    mn      = 'RDP%s' % rdptype
                    #h       -> {'Crohn': {'FS_FULL'    : BestReport instance,
                    #                      'FS_RELIEF'  : BestReport instance,
                    #                      'FS_BOTH'    : BestReport instance,
                    #                      }, ..}  
                    h       = getattr(self.bl,mn)
                    #h[i][j] -> BestReport instance
                    gg.append((h[i][j].avg.aa,h[i][j]))
                    ggAll.append((h[i][j].avg.aa,h[i][j]))
                #.bl.LHPCR[i][j] -> BestReport instance
                ggAll.append((self.bl.LHPCR[i][j].avg.aa,self.bl.LHPCR[i][j]))
                gg.sort(reverse = True)
                ggAll.sort(reverse = True)
                bestreport          = gg[0][1]
                self.bl.Both[i][j]  = bestreport
                bestreport_all      = ggAll[0][1]
                self.bl.All[i][j]   = bestreport_all 
        
    def dataDetail(self,mc,dset,dsort):
        #mc      -> MC instance
        #mainset -> {'rdp8level1_Entire_Healthy Control__Ulcerative Colitis': RESULTS instance,..}
        #dsort   -> ['rdp8level1_Entire_Healthy Control__Ulcerative Colitis',..]
        for i in range(len(dsort)):
            #dname       -> 'rdp8level1_Entire__Healthy Control__Ulcerative Colitis,'rdp8level1_Colon_Lumen__Crohn_Colon__Crohn_Lumen'
            dname               = dsort[i]                                 
            #mainname    -> 'Entire'
            mainname            = '_'.join(dname.split('__')[0].split('_')[1:])
            #subnamex    -> 'Healthy Control__Ulcerative Colitis'
            subnamex            = '__'.join(dname.split('__')[1:])
            #subname     -> 'Ulcerative Colitis'
            subname             = self.findMajor(subnamex)                            
            #result_obj  -> RESULTS instance
            result_obj          = dset[dname]                
            results_svm         = result_obj.results_svm
            results             = results_svm.results # List of UniverseDATA instances
            #mainhash    -> {'Healthy Control__Ulcerative Colitis: ..,..}                
            mainhash            = getattr(mc,mainname)
            mainhash[subname]   = {}                                
            #subcol      -> {'FS_FULL': Collect instance,..}
            subcol              = mainhash[subname]
            for j in results:
                #j -> UniverseDATA instance
                udata       = j
                if   udata.atpm.num == -1:
                    type_   = 'FS_FULL'
                elif udata.atpm.num != -1 and udata.SVMdrtn == SVMpm.Drtn.NORM:
                    type_   = 'FS_RELIEF'
                elif udata.atpm.num != -1 and udata.SVMdrtn in (SVMpm.Drtn.B2UP,SVMpm.Drtn.T2DW,):
                    type_   = 'FS_BOTH'
                subcol[type_]                           = Collect()
                subcol[type_].dname                     = dname
                pn                                      = subname.split('__')
                clsnum                                  = udata.ttcls.split('@')[1]
                if 'Healthy Control' in pn:
                    haveHealthy                         = True
                    subcol[type_].Positive              = pn[0] if pn[0] != 'Healthy Control' else pn[1]
                    subcol[type_].Negative              = pn[1] if pn[1] == 'Healthy Control' else pn[0]
                else:
                    haveHealthy                         = False
                    subcol[type_].Positive              = clsnum.split(';')[0].split(':')[0]
                    subcol[type_].Negative              = clsnum.split(';')[1].split(':')[0]
                if haveHealthy:
                    pnum                                = clsnum.split(';')[0].split(':')[1] \
                                                          if clsnum.split(';')[0].split(':')[0] != 'Healthy Control' \
                                                          else clsnum.split(';')[1].split(':')[1]
                    nnum                                = clsnum.split(';')[0].split(':')[1] \
                                                          if clsnum.split(';')[0].split(':')[0] == 'Healthy Control' \
                                                          else clsnum.split(';')[1].split(':')[1]
                else:
                    pnum                                = clsnum.split(';')[0].split(':')[1]
                    nnum                                = clsnum.split(';')[1].split(':')[1]
                #p_n -> '10/14' number of Positive/Negative
                subcol[type_].p_n                       = '%s/%s' % (pnum,nnum)
                if udata.ttcls_w != None:
                    clsnum_w                            = udata.ttcls_w.split('@')[1]
                    if haveHealthy:
                        pnum_w                          = clsnum_w.split(';')[0].split(':')[1] \
                                                          if clsnum_w.split(';')[0].split(':')[0] != 'Healthy Control' \
                                                          else clsnum_w.split(';')[1].split(':')[1]
                        nnum_w                          = clsnum_w.split(';')[0].split(':')[1] \
                                                          if clsnum_w.split(';')[0].split(':')[0] == 'Healthy Control' \
                                                          else clsnum_w.split(';')[1].split(':')[1]
                    else:
                        pnum_w                          = clsnum_w.split(';')[0].split(':')[1]
                        nnum_w                          = clsnum_w.split(';')[1].split(':')[1]
                    subcol[type_].p_n_w                 = '%s/%s' % (pnum_w,nnum_w)
                else:
                    subcol[type_].p_n_w                 = None
                subcol[type_].nf1                       = str(len(udata.data.domain.attributes))
                subcol[type_].nf2                       = str(len(udata.SVMbestatts))
#                subcol[type_].Accuracy                  = '%.2f' % (udata.SVMbestacc * 100)
                subcol[type_].Accuracy                  = '%.2f' % (udata.SVMbestacc,)
                if udata.SVMstat != None:
                    subcol[type_].AUC                   = udata.SVMaucs.split(';')[0].split('@')[1]
                    for k in udata.SVMstat.split(';'):
                        if k.split('@')[0] != 'Healthy Control':
                            subcol[type_].TP            = k.split('@')[1].split(':')[0]
                            subcol[type_].FP            = k.split('@')[1].split(':')[1]
                            subcol[type_].FN            = k.split('@')[1].split(':')[2]
                            subcol[type_].TN            = k.split('@')[1].split(':')[3]
                            subcol[type_].Sens          = k.split('@')[1].split(':')[4]
                            subcol[type_].Spec          = k.split('@')[1].split(':')[5]
                            subcol[type_].PPV           = k.split('@')[1].split(':')[6]
                            subcol[type_].NPV           = k.split('@')[1].split(':')[7]
                            subcol[type_].F1            = k.split('@')[1].split(':')[8]
                            break
        return mc
    
    def dataAverage(self,mc):
        FS  = mc.FS
        for j in self.u_list_all:
            #j -> 'Crohn'
            if   j in self.u_list_norm:
                ak  = self.s_list_a
            elif j in self.u_list_lumen:
                ak  = self.s_list_b
            for k in FS[j]:
                #k -> 'FS_FULL'
                acc_sum = []
                auc_sum = []
                for m in ak:
                    #k -> 'Entire'
                    #g -> 
                    #{'Crohn__Healthy Control': 
                    #                           {'FS_FULL'  : Collect instance    ,
                    #                            'FS_RELIEF': Collect instance    ,
                    #                            'FS_BOTH'  : Collect instance    ,
                    #                             },..}
                    g           = getattr(mc,m)
                    #y -> Collect instance
                    collect     = g[j][k]
#                    acc         = float(collect.Accuracy)/100.
                    acc         = float(collect.Accuracy)
                    auc         = float(collect.AUC)
                    acc_sum.append(acc)
                    auc_sum.append(auc)
                FS[j][k].acc_avg    = numpy.mean(acc_sum)
                FS[j][k].auc_avg    = numpy.mean(auc_sum)
                FS[j][k].aa         = numpy.mean([FS[j][k].acc_avg,FS[j][k].auc_avg])
        return mc
    
    def startRecording(self):
        accauc  = ['Average','AA (Accuracy + AUC)',]
        bestlv  = ['Best Level',]                
        for i in range(1,15):
            self.sheet[self.RDP8_s_n].col(i).width  = self.col_width
            self.sheet[self.RDP10_s_n].col(i).width = self.col_width
            self.sheet[self.ALH_s_n].col(i).width = self.col_width
            self.sheet[self.VS_s_n].col(i).width    = self.col_width
        c_col   = 1
        c_row   = 1                   
        #Record RDP 8 and 10 
        for typex in GUTIBD.rdpType.LIST:
            #i -> 'RDP8'
            i   = 'RDP%s' % typex            
            for j in self.u_list_all:
                #j -> 'Crohn'
                if   j in self.u_list_norm:
                    ak  = self.s_list_a
                elif j in self.u_list_lumen:
                    ak  = self.s_list_b
                head        = ak + accauc + bestlv
                self.c_col  = c_col
                self.c_row  = c_row
                self.sheet[i].write(self.c_row,self.c_col,j)                
                for k in range(len(head)):
                    self.sheet[i].write(self.c_row,self.c_col + k + 3,head[k])
                self.ri()
                for k in self.t_list:
                    #k -> 'FS_FULL'
                    self.sheet[i].write(self.c_row,self.c_col,k)
                    best_row    = self.c_row
                    rdptype     = typex
                    if   rdptype == GUTIBD.rdpType.Eight:
                        slist       = GUTIBD.rdpList.LIST
                    elif rdptype == GUTIBD.rdpType.Ten:
                        slist       = GUTIBD.rdpList.LIST10
                    for rdplevel in slist:
                        rdpdbname   = self.rdp2dbName(rdplevel,rdptype)
                        self.sheet[i].write(self.c_row      ,self.c_col + 1,rdpdbname.upper())
                        self.sheet[i].write(self.c_row      ,self.c_col + 2,'Accuracy')
                        self.sheet[i].write(self.c_row + 1  ,self.c_col + 2,'AUC')
                        self.ci()
                        self.ci()
                        self.ci()
                        for n in ak:
                            #n        -> 'Entire','Ileum_Lumen'
                            mc  = getattr(self.collect[rdpdbname],n)
                            #mc[j][k] -> mc['Crohn']['FS_FULL']
                            #cl       -> Collect instance
                            cl  = mc[j][k]
                            self.sheet[i].write(self.c_row      ,self.c_col,cl.Accuracy)
                            self.sheet[i].write(self.c_row + 1  ,self.c_col,cl.AUC)
                            self.ci()
                        FS          = self.collect[rdpdbname].FS
                        #avg -> AVG instance
                        avg         = FS[j][k]
                        self.sheet[i].write(self.c_row      ,self.c_col,'%.2f' % (avg.acc_avg,))
                        self.sheet[i].write(self.c_row + 1  ,self.c_col,'%.2f' % (avg.auc_avg,))
                        self.ci()
                        self.sheet[i].write(self.c_row      ,self.c_col,'%.2f' % (avg.aa,))
                        best_col    = self.c_col + 1
                        self.c_col  = 1
                        self.ri()
                        self.ri()
                    #bLevel -> BestLevel.RDP8
                    bLevel  = getattr(self.bl,i)
                    #br     -> BestReport instance
                    br      = bLevel[j][k]
                    self.sheet[i].write(best_row,best_col,br.level)                        
                c_col   = 1
                c_row   = self.c_row
            c_col   = 1
            c_row   = 1
        #Record ALH
        c_col       = 1
        c_row       = 1
        q           = self.ALH_s_n
        for i in self.u_list_all:
            #i -> 'Crohn'
            if   i in self.u_list_norm:
                ak  = self.s_list_a
            elif i in self.u_list_lumen:
                ak  = self.s_list_b
            head        = ak + accauc
            self.c_col  = c_col
            self.c_row  = c_row
            self.sheet[q].write(self.c_row,self.c_col,i)                
            for j in range(len(head)):
                self.sheet[q].write(self.c_row,self.c_col + j + 2,head[j])
            self.ri()
            for j in self.t_list:
                #j -> 'FS_FULL'
                self.sheet[q].write(self.c_row      ,self.c_col         ,j          )
                self.sheet[q].write(self.c_row      ,self.c_col + 1     ,'Accuracy' )
                self.sheet[q].write(self.c_row + 1  ,self.c_col + 1     ,'AUC'      )
                self.ci()
                self.ci()
                for n in ak:
                    #n        -> 'Entire','Ileum_Lumen'
                    mc  = getattr(self.lhpcr_mc,n)
                    #mc[i][j] -> mc['Crohn']['FS_FULL']
                    #cl       -> Collect instance
                    cl  = mc[i][j]
                    self.sheet[q].write(self.c_row      ,self.c_col ,cl.Accuracy)
                    self.sheet[q].write(self.c_row + 1  ,self.c_col ,cl.AUC)
                    self.ci()
                FS          = self.lhpcr_mc.FS
                #avg -> AVG instance
                avg         = FS[i][j]
                self.sheet[q].write(self.c_row      ,self.c_col,'%.2f' % (avg.acc_avg,))
                self.sheet[q].write(self.c_row + 1  ,self.c_col,'%.2f' % (avg.auc_avg,))
                self.ci()
                self.sheet[q].write(self.c_row      ,self.c_col,'%.2f' % (avg.aa,))
                self.c_col  = 1
                self.ri()
                self.ri()                     
            c_col   = 1
            c_row   = self.c_row
        #Both Report
        ss          = self.VS_s_n
        headBoth    = ['BEST RDP8','AA','BEST RDP10','AA','BEST TAXA','ALH','AA','Best',]        
        c_col       = 1
        c_row       = 1     
        cnt_d       = 0
        cnt_s       = 0
        for i in self.u_list_all:
            #i -> 'Crohn'
            self.c_col  = c_col
            self.c_row  = c_row
            if i in self.d_list:
                if cnt_d == 0:
                    self.sheet[ss].write(self.c_row,self.c_col,'Disease-Specific')
                    self.ri()
                    cnt_d += 1
            else:
                if cnt_s == 0:
                    self.ri()
                    self.sheet[ss].write(self.c_row,self.c_col,'Site-Specific')
                    self.ri()
                    cnt_s += 1
            self.sheet[ss].write(self.c_row,self.c_col,i)
            self.ci()
            for j in range(len(headBoth)):
                self.sheet[ss].write(self.c_row,self.ci(),headBoth[j])
            self.c_col  = 1
            self.ri()
            for j in self.t_list:
                #j -> 'FS_FULL'
                self.sheet[ss].write(self.c_row,self.c_col,j)
                self.ci()
                for rdptype in GUTIBD.rdpType.LIST:
                    #rdptype -> '8'
                    #typex   -> 'RDP8'
                    typex   = 'RDP%s' % rdptype
                    #brone   -> BestLevel.RDP8
                    brone   = getattr(self.bl,typex)
                    #brx     -> BestReport instance
                    brx     = brone[i][j]
                    self.sheet[ss].write(self.c_row,self.c_col      ,brx.level              )
                    self.sheet[ss].write(self.c_row,self.c_col + 1  ,'%.2f' % brx.avg.aa    )
                    self.ci()
                    self.ci() 
                    #BestLevel.Both[i][j] -> BestReport instance 
                brboth      = self.bl.Both[i][j]
                self.sheet[ss].write(self.c_row,self.c_col,brboth.level)
                self.ci()
                #br_lhpcr -> BestReport instance
                br_lhpcr    = self.bl.LHPCR[i][j]
                self.sheet[ss].write(self.c_row,self.c_col      ,br_lhpcr.level)
                self.sheet[ss].write(self.c_row,self.c_col + 1  ,'%.2f' % br_lhpcr.avg.aa)
                brall       = self.bl.All[i][j]
                self.sheet[ss].write(self.c_row,self.c_col + 2  ,brall.level)
                self.c_col  = 1
                self.ri()
            c_col  = 1
            c_row  = self.c_row
    
    def rdp2dbName(self,rdplevel,rdptype):
        rdpname = rdplevel.replace(' ','').lower()
        rdpname = rdpname.replace('rdp','rdp%s' % rdptype)
        return rdpname
    
    def saveBook(self):
        self.book.save(self.output_file)             
                
    def ci(self):
        self.c_col += 1
        #Increase and return current column
        return self.c_col - 1
    
    def ri(self):
        self.c_row += 1
        return self.c_row - 1


class MC(object):

    def __init__(self):
        #For each level like 'rdp8level1'
        #{'Crohn': 
        #                           {'FS_FULL'  : Collect instance,
        #                            'FS_RELIEF': Collect instance,
        #                            'FS_BOTH'  : Collect instance,
        #                             },
        # 'Healthy Control': 
        #                           {'FS_FULL'  : Collect instance,
        #                            'FS_RELIEF': Collect instance,
        #                            'FS_BOTH'  : Collect instance,
        #                             },
        #}
        self.Entire         = {}
        self.Ileum          = {}
        self.Colon          = {}
        self.Sigmoid        = {}
        self.Lumen          = {}
        self.Ileum_Lumen    = {}
        self.Colon_Lumen    = {}
        self.Sigmoid_Lumen  = {}
        self.u_list_a       = ['Crohn','Ulcerative Colitis','Crohn_Lumen','Ulcerative Colitis_Lumen','Healthy Control_Lumen']
        self.t_list         = ['FS_FULL','FS_RELIEF','FS_BOTH',]
        #self.FS -> 
        #{'Crohn': 
        #                           {'FS_FULL'  : AVG instance,
        #                            'FS_RELIEF': AVG instance,
        #                            'FS_BOTH'  : AVG instance,
        #                             },
        # 'Ulcerative Colitis': 
        #                           {'FS_FULL'  : AVG instance,
        #                            'FS_RELIEF': AVG instance,
        #                            'FS_BOTH'  : AVG instance,
        #                             },
        #}        
        self.FS             = {}
        for i in self.u_list_a:
            self.FS[i] = {}
            for j in self.t_list:
                self.FS[i][j] = AVG()
         
            
class Collect(object):
    
    def __init__(self,**kwargs):
        #These attributes are used to write in excel
        self.dname          = '' #datasetname
        self.Positive       = ''
        self.Negative       = ''
        self.p_n            = ''
        self.p_n_w          = ''
        self.nf1            = '' #Number of features 1st stage
        self.nf2            = '' #Number of features 2nd stage
        self.Accuracy       = ''
        self.AUC            = ''
        self.TP             = ''
        self.FP             = ''
        self.FN             = ''
        self.TN             = ''
        self.Sens           = ''
        self.Spec           = ''
        self.PPV            = ''
        self.NPV            = ''
        self.F1             = ''        
        self.__dict__.update(kwargs)


class AVG(object):
    
    def __init__(self):
        self.acc_avg   = 0.0
        self.auc_avg   = 0.0
        self.aa        = 0.0 #(acc_avg + auc_avg)/2.


class BestLevel(object):
    
    def __init__(self):
        #.RDP8 -> {'Crohn': {'FS_FULL'    : BestReport instance,
        #                    'FS_RELIEF'  : BestReport instance,
        #                    'FS_BOTH'    : BestReport instance,
        #                    }, ..}
        self.RDP8   = {}
        self.RDP10  = {}
        self.LHPCR  = {}
        #.Both -> {'Crohn': {'FS_FULL'    : BestReport instance,
        #                    'FS_RELIEF'  : BestReport instance,
        #                    'FS_BOTH'    : BestReport instance,
        #                    }, ..} 
        self.Both   = {}
        #.All  -> {'Crohn': {'FS_FULL'    : BestReport instance,
        #                    'FS_RELIEF'  : BestReport instance,
        #                    'FS_BOTH'    : BestReport instance,
        #                    }, ..}
        self.All    = {}
        
        
class BestReport(object):
    
    def __init__(self,**kwargs):
        self.level  = ''
        self.avg    = None #AVG instance
        self.__dict__.update(kwargs)





        